import {$$notice, PlButton, PlDropdown, PlDropdownMenu, PlDropdownOption, PlIcon} from "plain-ui";
import {designComponent, onMounted, reactive} from "plain-ui-composition";
import {PublicApp} from "../PublicRoot";
import './RunApp.scss'
import {getSingleMdcCase, MdcCase, processVueCode} from "../index/mdc/process/processCaseString";
import {useRunSeparator} from "./useRunSeparator";
import {throttle} from "plain-utils/utils/throttle";
import {MdcCaseComponent} from "../index/mdc/mdc-case";
import {MonacaEditor} from "./editor/MonacoEditor";
import {IKeyboardEvent} from "monaco-editor";
import {deepcopy} from "plain-utils/object/deepcopy";

export const RunApp = designComponent({
    setup() {

        const state = reactive({
            mdc: null as null | MdcCase,
            runMdc: null as null | MdcCase,
            bindCode: '',
            runCode: '',
        })

        const separator = useRunSeparator()

        const utils = {
            encodeCodeString(jsx: string, css?: string): string {
                return `<script>\n${jsx}\n</script>` + `\n\n<style>${!css ? '\n' : `\n${css || ''}\n`}</style>`
            },
            decodeCodeString(codeString: string): { jsx: string, css?: string } {
                const matchJsx = /<script>((?:.|\r|\n|\t)*)<\/script>/.exec(codeString)
                if (!matchJsx) {
                    const msg = '代码格式不正确！';
                    (window as any).codeString = codeString
                    $$notice.error(msg)
                    throw new Error(msg)
                }
                const jsx = matchJsx[1]
                const matchCss = /<style>((?:.|\r|\n|\t)*)<\/style>/.exec(codeString)
                const css = !!matchCss ? matchCss[1] : undefined
                return {jsx, css}
            },
            preview: async (code: string) => {
                state.runCode = deepcopy(code)
                const {source, template, js, css} = processVueCode(code)
                return state.runMdc = {...state.mdc!, source, template, js, css}
            },
            run: throttle(() => {
                if (state.bindCode == state.runCode) {
                    return
                }
                utils.preview(state.bindCode)
                // ctx.$notice('刷新完毕！')
            }, 2000),
            reset: () => {
                if (!state.mdc || (!state.mdc.template && !state.mdc.js)) {return}
                const {source} = state.mdc
                state.bindCode = source
            },
            share: () => {
                $$notice.warn('功能未发布，敬请期待')
            },
            saveLocal: () => {
                $$notice.warn('功能未发布，敬请期待')
            },
        }

        onMounted(async () => {
            const search = window.location.search.slice(1).split('&').map(search => {
                const [key, val] = search.split('=')
                return {
                    key, val
                }
            }).reduce((ret, item) => {
                // @ts-ignore
                ret[item.key] = item.val
                return ret
            }, {} as { path: string, index: string })

            try {
                const str = (await import('@/doc/' + search.path + '.md')).default;
                const mdc = getSingleMdcCase(str, Number(search.index))
                state.mdc = mdc
                if (!mdc || (!mdc.template && !mdc.js)) {return}
                const {source} = mdc
                state.bindCode = source
                utils.preview(state.bindCode)
            } catch (e) {
                console.error(e)
                $$notice.error(String(e))
            }
        })

        function onEditorKeydown(ie: IKeyboardEvent) {
            const e = ie.browserEvent
            if ((!!e.ctrlKey || !!e.metaKey) && e.keyCode === 83) {
                e.stopPropagation()
                e.preventDefault()
                utils.run()
            }
        }

        return {
            render: () => {
                return (
                    <PublicApp>
                        <div class="app-run">
                            <div class="app-run-head">
                                <div class="app-run-head-left">
                                    <span class='app-run-head-title'>
                                        PLAIN
                                    </span>
                                    <div class="app-run-head-operator">
                                        <PlButton icon="el-icon-video-play" label="运行" mode="text" onClick={utils.run}/>
                                        <PlButton icon="el-icon-refresh" label="重置" mode="text" onClick={utils.reset}/>
                                        <PlButton icon="el-icon-share" label="分享" mode="text" onClick={utils.share}/>
                                        <PlButton icon="el-icon-document" label="保存到本地" mode="text" onClick={utils.saveLocal}/>
                                        <PlDropdown
                                            placement="bottom-end"
                                            v-slots={{
                                                default: () => (
                                                    <PlButton mode="text">
                                                        <span>视图</span>
                                                        <PlIcon icon="el-icon-arrow-down"/>
                                                    </PlButton>
                                                ),
                                                popper: () => (
                                                    <PlDropdownMenu>
                                                        <PlDropdownOption label="代码与预览" icon='el-icon-debug-s' onClick={utils.saveLocal}/>
                                                        <PlDropdownOption label="仅显示代码" icon="el-icon-code" onClick={utils.saveLocal}/>
                                                        <PlDropdownOption label="仅显示预览" icon="el-icon-view" onClick={utils.saveLocal}/>
                                                    </PlDropdownMenu>
                                                )
                                            }}
                                        />
                                    </div>
                                </div>
                            </div>
                            <div class="app-run-code" style={separator.styles.value.code} key={separator.styles.value.code.width}>
                                <MonacaEditor v-model={state.bindCode} language={'html'} onKeydown={onEditorKeydown}/>
                            </div>
                            <div class="app-run-case" style={separator.styles.value.case}>
                                {!!state.runMdc && <MdcCaseComponent mdc={state.runMdc} onlyCase/>}
                            </div>
                            {separator.render()}
                        </div>
                    </PublicApp>
                )
            }
        }
    },
})
